//////////////////////////////////////////////////////////////////////////
// $Id: MainView.cpp,v 1.2 2009/01/04 12:43:07 sunjun Exp $
//////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MainApp.h"
#include "MainView.h"

//////////////////////////////////////////////////////////////////////////

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//////////////////////////////////////////////////////////////////////////

MainView::MainView()
{
	
}

MainView::~MainView()
{

}

//////////////////////////////////////////////////////////////////////////

BEGIN_MESSAGE_MAP(MainView, CWnd)	
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_PAINT()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_MOUSEWHEEL()
	ON_WM_TIMER()
	ON_WM_ERASEBKGND()
END_MESSAGE_MAP()

//////////////////////////////////////////////////////////////////////////

// MainView message handlers
int MainView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CWnd::OnCreate(lpCreateStruct) == -1) return -1;

	// init the frame timer
	SetTimer( TIMER_PAINT, 30, NULL );	

	std::vector<U32>a;

	return 0;
}

void MainView::OnDestroy()
{
	CWnd::OnDestroy();
}

void MainView::OnTimer(UINT_PTR nIDEvent)
{
	switch( nIDEvent )
	{
	case TIMER_PAINT:
		RedrawWindow( NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW );
		break;
	}

	CWnd::OnTimer(nIDEvent);
}

void MainView::OnPaint() 
{
	CPaintDC dc(this);

	run();
}

BOOL MainView::OnEraseBkgnd(CDC* pDC)
{
	return FALSE;
	// return CWnd::OnEraseBkgnd(pDC);
}

void MainView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}

void MainView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
}

void MainView::OnLButtonDown(UINT nFlags, CPoint point)
{
	CWnd::OnLButtonDown(nFlags, point);
}

void MainView::OnLButtonUp(UINT nFlags, CPoint point)
{
	CWnd::OnLButtonUp(nFlags, point);
}

void MainView::OnRButtonDown(UINT nFlags, CPoint point)
{
	CWnd::OnRButtonDown(nFlags, point);
}

void MainView::OnRButtonUp(UINT nFlags, CPoint point)
{
	CWnd::OnRButtonUp(nFlags, point);
}

void MainView::OnMouseMove(UINT nFlags, CPoint point)
{	
	CWnd::OnMouseMove(nFlags, point);
}

BOOL MainView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
	return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}

//////////////////////////////////////////////////////////////////////////

VOID MainView::init()
{
	// load the plugins
	MOS::instance().loadPlugin("render");
	MOS::instance().loadPlugin("engine");

	// create the graph context
	mGraphPtr = new Graph; CHECK(mGraphPtr);
	mGraphPtr->bind( this->GetSafeHwnd() );

	ConstantPtr constant_ptr = new Constant; CHECK( constant_ptr );
	constant_ptr->setMatrix(Matrix());
	mWVPPtr = new Dict::Key("gWVP", constant_ptr.ptr());

	// read the mesh file
	MFile file;
	CHECK(file.open( "models/mesh.xml" ));
	U32 pos = file.tell();
	file.seek(0,2);
	U32 size = file.tell();
	file.seek(pos,0);
	MDataPtr data_ptr = new MData;
	CHECK(data_ptr);
	data_ptr->resize(size);
	CHECK(file.read(data_ptr.ptr())==size);
	file.close();

	mMeshPtr = new Mesh; CHECK(mMeshPtr);
	mMeshPtr->bind( mGraphPtr.ptr() );
	mMeshPtr->load( data_ptr.ptr() );
}

VOID MainView::run()
{
	if( mGraphPtr == NULL ) return;

	// get the window rect
	RECT rc;
	this->GetClientRect(&rc);

	mFov = 90.0;
	mAspect = (F32)(rc.right-rc.left)/(F32)(rc.bottom-rc.top);
	mZNear = 1.0;
	mZFar = 2000.0;
	mEye.set(-1000,0,0); 
	mCenter.set(0,0,0); 
	mUp.set(0,0,1);

	// begin the scene
	ScenePtr begin_scene = new Scene(Scene::ST_BEGIN);
	mGraphPtr->exec( begin_scene.ptr() );

	// the view
	ViewPtr view_ptr = new View; CHECK(view_ptr);

	// set the viewport
	ViewportPtr viewport = new Viewport;
	viewport->set(0,0,rc.right-rc.left,rc.bottom-rc.top,0,1);
	mGraphPtr->exec( viewport.ptr() );

	// clear the target and the zbuffer
	ClearPtr clear = new Clear;
	clear->set(Clear::CT_TARGET|Clear::CT_ZBUFFER,0,1.0,0);
	mGraphPtr->exec( clear.ptr() );	

	// make the projection and the view
	Matrix proj_mat = Matrix::makePerspective(mFov,mAspect,mZNear,mZFar);
	Matrix view_mat = Matrix::makeLookAt(mEye,mCenter,mUp);
	Matrix world_view_proj_mat = view_mat * proj_mat;
	dynamic_cast<Constant*>(mWVPPtr->ptr())->setMatrix(world_view_proj_mat);

	// draw the mesh
	mMeshPtr->draw(view_ptr.ptr());

	// end the scene
	ScenePtr end_scene = new Scene(Scene::ST_END);
	mGraphPtr->exec( end_scene.ptr() );

	// swap the operation to the render thread
	mGraphPtr->swap();
}

VOID MainView::exit()
{
	if( mMeshPtr ) mMeshPtr.release();
	if( mWVPPtr ) mWVPPtr.release();

	// release the rc 
	if( mGraphPtr ) { mGraphPtr->bind( NULL ); mGraphPtr.release(); }

	// free all of the plugin
	MOS::instance().freePlugin("engine");
	MOS::instance().freePlugin("render");	
}

//////////////////////////////////////////////////////////////////////////
